import {
  isUndefined,
  BackendServices,
  canUse,
  Stages,
  isStages,
  StringIndexer,
} from "mmb";
import { Client } from "grpc";
import store, { GrpcService, MicroServiceConf } from "./index";
import * as config from "../conf/config.json";

export const loadConfAndEnv = () => {
  // env
  let stage = process.env.STAGE;
  if (isStages(stage)) {
    setEnvStage(stage);
  }

  // bgs
  let grpcBgsAddress = process.env.GRPC_BGS_ADDRESS;
  if (isUndefined(grpcBgsAddress)) {
    console.log("not found env GRPC_BGS_ADDRESS. use predefined conf");
    grpcBgsAddress = config.bgs.grpc;
  }
  console.log(`grpc bgs address=>${grpcBgsAddress}`);
  setGrpcAddress(BackendServices.BGS)(grpcBgsAddress);

  // account
  let grpcAccountAddress = process.env.GRPC_ACCOUNT_ADDRESS;
  if (isUndefined(grpcAccountAddress)) {
    console.log("not found env GRPC_ACCOUNT_ADDRESS. use predefined conf");
    grpcAccountAddress = config.account.grpc;
  }
  console.log(`grpc account address=>${grpcAccountAddress}`);
  setGrpcAddress(BackendServices.ACCOUNT)(grpcAccountAddress);

  // bilinadmin
  let grpcBilinAdminAddress = process.env.GRPC_BILIN_ADMIN_ADDRESS;
  if (isUndefined(grpcBilinAdminAddress)) {
    console.log("not found env GRPC_BILIN_ADMIN_ADDRESS. use predefined conf");
    grpcBilinAdminAddress = config.bilinadmin.grpc;
  }
  console.log(`grpc bilinadmin address=>${grpcBilinAdminAddress}`);
  setGrpcAddress(BackendServices.BILIN_ADMIN)(grpcBilinAdminAddress);

  // gsms
  let grpcGsmsAddress = process.env.GRPC_GSMS_ADDRESS;
  if (isUndefined(grpcGsmsAddress)) {
    console.log("not found env GRPC_GSMS_ADDRESS. use predefined conf");
    grpcGsmsAddress = config.gsms.grpc;
  }
  console.log(`grpc gsms address=>${grpcGsmsAddress}`);
  setGrpcAddress(BackendServices.GSMS)(grpcGsmsAddress);

  // inventory
  let grpcInventoryAddress = process.env.GRPC_INVENTORY_ADDRESS;
  if (isUndefined(grpcInventoryAddress)) {
    console.log("not found env GRPC_INVENTORY_ADDRESS. use predefined conf");
    grpcInventoryAddress = config.inventory.grpc;
  }
  console.log(`grpc inventory address=>${grpcInventoryAddress}`);
  setGrpcAddress(BackendServices.INVENTORY)(grpcInventoryAddress);

  // web-pos
  let apiWebposAddress = process.env.API_WEBPOS_ADDRESS;
  if (isUndefined(apiWebposAddress)) {
    console.log("not found env API_WEBPOS_ADDRESS. use predefined conf");
    apiWebposAddress = config.webpos.api;
  }
  console.log(`api webpos address=>${apiWebposAddress}`);
  setApiAddress(BackendServices.WEBPOS)(apiWebposAddress);

  // wxpay
  let grpcWxpayAddress = process.env.GRPC_WXPAY_ADDRESS;
  if (isUndefined(grpcWxpayAddress)) {
    console.log("not found env GRPC_WXPAY_ADDRESS. use predefined conf");
    grpcWxpayAddress = config.wxpay.grpc;
  }
  console.log(`grpc wxpay address=>${grpcWxpayAddress}`);
  setGrpcAddress(BackendServices.WXPAY)(grpcWxpayAddress);
  let apiWxpayAddress = process.env.API_WXPAY_ADDRESS;
  if (isUndefined(apiWxpayAddress)) {
    console.log("not found env API_WXPAY_ADDRESS. use predefined conf");
    apiWxpayAddress = config.wxpay.api;
  }
  console.log(`api webpos address=>${apiWxpayAddress}`);
  setApiAddress(BackendServices.WXPAY)(apiWxpayAddress);
  setVars(BackendServices.WXPAY)(config.wxpay.vars)

  // nsq
  let lookupdAddress = process.env.LOOUPD_ADDRESS;
  if (isUndefined(lookupdAddress)) {
    console.log("not found env LOOUPD_ADDRESS. use predefined conf");
    lookupdAddress = config.nsq.lookupd;
  }
  console.log(`mq lookupdAddress=>${lookupdAddress}`);
  setLookupdAddress(lookupdAddress);

  let nsqdAddress = process.env.NSQD_ADDRESS;
  if (isUndefined(nsqdAddress)) {
    console.log("not found env NSQD_ADDRESS. use predefined conf");
    nsqdAddress = config.nsq.nsqd;
  }
  console.log(`mq nsqdAddress=>${nsqdAddress}`);
  setNsqdAddress(nsqdAddress);

  // redis
  let redisAddress = process.env.REDIS_ADDRESS;
  if (isUndefined(redisAddress)) {
    console.log("not found env REDIS_ADDRESS. use predefined conf");
    redisAddress = config.redis.address;
  }
  console.log(`redis address=>${redisAddress}`);
  setRedisAddress(redisAddress);

  let redisPassword = process.env.REDIS_PASSWORD;
  if (isUndefined(redisPassword)) {
    console.log("not found env REDIS_PASSWORD. use predefined conf");
    redisPassword = config.redis.password;
  }
  console.log(`redis password=>${redisPassword}`);
  setRedisPassword(redisPassword);
};

export const getEnvStage = (): Stages => {
  return store.envs.stage;
};

export const setEnvStage = (v: Stages) => {
  if (canUse(v)) {
    store.envs.stage = v;
  }
};

export const getConf = (k: BackendServices) => {
  return store.confs[k];
};

export const setConf = (k: BackendServices, v: MicroServiceConf) => {
  if (canUse(v)) {
    store.confs[k] = v;
  }
};

export const getGrpcAddress = (s: BackendServices) => {
  return () => {
    let conf = getConf(s);
    if (!canUse(conf)) {
      return null;
    }
    console.log("conf.grpc=>", conf.grpc);
    return conf.grpc;
  };
};

export const getApiAddress = (s: BackendServices) => {
  return () => {
    let conf = getConf(s);
    if (!canUse(conf)) {
      return null;
    }
    return conf.api;
  };
};

export const getVars = (s: BackendServices) => {
  return () => {
    let conf = getConf(s);
    if (!canUse(conf)) {
      return undefined;
    }
    return conf.vars;
  };
};

export const getVar = (s: BackendServices) => {
  return (k: string) => {
    let conf = getConf(s);
    if (!canUse(conf)) {
      return undefined;
    }
    if (isUndefined(conf.vars)) {
      return undefined
    }
    return conf.vars[k];
  };
};

export const setGrpcAddress = (s: BackendServices) => {
  return (v: string) => {
    let conf = getConf(s);
    if (!canUse(conf)) {
      setConf(s, { grpc: null, api: null, vars: undefined });
      conf = getConf(s);
    }
    if (canUse(v)) {
      conf.grpc = v;
    }
  };
};

export const setApiAddress = (s: BackendServices) => {
  return (v: string) => {
    let conf = getConf(s);
    if (!canUse(conf)) {
      setConf(s, { grpc: null, api: null, vars: undefined });
      conf = getConf(s);
    }
    if (canUse(v)) {
      conf.api = v;
    }
  };
};

export const setVars = (s: BackendServices) => {
  return (v: StringIndexer) => {
    let conf = getConf(s);
    if (!canUse(conf)) {
      setConf(s, { grpc: null, api: null, vars: undefined });
      conf = getConf(s);
    }
    if (canUse(v)) {
      conf.vars = v;
    }
  };
};

export const setVar = (s: BackendServices) => {
  return (k: string, v: any) => {
    let conf = getConf(s);
    if (!canUse(conf)) {
      setConf(s, { grpc: null, api: null, vars: undefined });
      conf = getConf(s);
    }
    if (isUndefined(conf.vars)) {
      conf.vars = {};
    }
    conf.vars[k] = v;
  };
};

export const setLookupdAddress = (v: string) => {
  store.mq.nsq.lookupd = v;
};

export const getLookupdAddress = () => {
  return store.mq.nsq.lookupd;
};

export const setNsqdAddress = (v: string) => {
  store.mq.nsq.nsqd = v;
};

export const getNsqdAddress = () => {
  return store.mq.nsq.nsqd;
};

export const setRedisAddress = (v: string) => {
  store.redis.address = v;
};

export const getRedisAddress = () => {
  return store.redis.address;
};

export const setRedisPassword = (v: string) => {
  store.redis.password = v;
};

export const getRedisPassword = () => {
  return store.redis.password;
};

export const getGrpcService = (k: BackendServices) => {
  return store.grpcServices[k];
};

export const setGrpcService = (k: BackendServices, v: GrpcService) => {
  if (canUse(v)) {
    store.grpcServices[k] = v;
  }
};

export const getGrpcClient = (s: BackendServices) => {
  return (k: string) => {
    let srv = getGrpcService(s);
    if (!canUse(srv)) {
      return null;
    }
    return srv[k];
  };
};

export const setGrpcClient = (s: BackendServices) => {
  return (k: string, v: Client) => {
    let srv = getGrpcService(s);
    if (!canUse(srv)) {
      setGrpcService(s, {});
      srv = getGrpcService(s);
    }
    if (canUse(v)) {
      srv[k] = v;
    }
  };
};